--======================================================================
--（c）copyright 2016 175game.com All Rights Reserved
--======================================================================
-- anthor: hy
-- descrip: 协议管理器，主要负责协议上行和下行
--======================================================================

local Cprotocol = Import("logic/net/protocol").Cprotocol
local Crpc = Import("logic/net/rpc").Crpc

--Import各个模块的协议接口--BEGIN
Import("logic/net/login_protocol")
Import("logic/net/hero_protocol")
Import("logic/net/scene_protocol")
Import("logic/net/summon_protocol")
Import("logic/net/msg_protocol")
Import("logic/net/npc_protocol")
Import("logic/net/fight_protocol")
Import("logic/net/task_protocol")
Import("logic/net/item_protocol")
Import("logic/net/equip_protocol")
Import("logic/net/deliver_protocol")
Import("logic/net/team_protocol")
Import("logic/net/onoff_protocol")
Import("logic/net/other_protocol")
Import("logic/net/skill_protocol")
-- Import("logic/net/mingge_protocol")
Import("logic/net/exam_protocol")
Import("logic/net/chat_protocol")
Import("logic/net/achieve_protocol")
Import("logic/net/partner_protocol")
Import("logic/net/fuben_protocol")
Import("logic/net/faction_protocol")
Import("logic/net/arean_protocol")
Import("logic/net/fetter_protocol")
Import("logic/net/mail_protocol")
Import("logic/net/paoshang_protocol")
Import("logic/net/friend_protocol")
Import("logic/net/rank_protocol")
Import("logic/net/activity_protocol")
Import("logic/net/map_protocol")
Import("logic/net/activity_mystery_protocol")
Import("logic/net/stall_protocol")
Import("logic/net/tower_protocol")
Import("logic/net/tower_team_protocol")
Import("logic/net/play_fairyland_protocol")
Import("logic/net/play_summon_protocol")
Import("logic/net/wanted_protocol")
Import("logic/net/red_point_protocol")
Import("logic/net/active_protocol")
Import("logic/net/org_fight_protocol")
Import("logic/net/status_protocol")
Import("logic/net/chumo_protocol")
Import("logic/net/fish_protocol")
Import("logic/net/hunt_protocol")
Import("logic/net/robot_protocol")
Import("logic/net/answerpk_protocol")
Import("logic/net/gift_protocol")
Import("logic/net/guardian_war_protocol")
Import("logic/net/play_collect_item_protocol")
Import("logic/net/org_practice_protocol")
Import("logic/net/patrol_hang_up_protocol")
Import("logic/net/qunying_protocol")
Import("logic/net/yuanshen_protocol")
Import("logic/net/org_boss_protocol")
Import("logic/net/org_slg_protocol")
Import("logic/net/org_develop_protocol")
Import("logic/net/play_org_banquet_protocol")
Import("logic/net/tianjie_protocol")
Import("logic/net/org_shop_protocol")
Import("logic/net/rank_tips_protocol")
Import("logic/net/tujian_protocol")
Import("logic/net/trade_protocol")
Import("logic/net/news_protocol")
Import("logic/net/org_thief_protocol")
Import("logic/net/catch_summon_protocol")
Import("logic/net/wabao_protocol")
Import("logic/net/photo_protocol")
Import("logic/net/life_skill_protocol")
Import("logic/net/out_fight_status_protocol")
Import("logic/net/game_time_protocol")
Import("logic/net/team_pk_protocol")
Import("logic/net/org_produce_protocol")
Import("logic/net/org_new_protocol")
Import("logic/net/org_mission_protocol")
Import("logic/net/org_recycle_protocol")
Import("logic/net/org_hall_protocol")
Import("logic/net/spacetime_protocol")
--Import各个模块的协议接口--END

local MAX_RPC_PER_FRAME = 50

local RPC_CLIENT_CHAT_PARSE_COUNT = 2
local RPC_CLIENT_CHAT_PARSE_DELTATIME = 0.4

local RPC_USE_CACHE =
{
	["rpc_client_chat"] = true,
}

CProtocolManager = class()

CProtocolManager.Init = function(self)
	UpdateBeat:Add(self.Update, self)

	gGame:GetTimeManager():AddTimer(RPC_CLIENT_CHAT_PARSE_DELTATIME, function()
		self:UpdateSpecialCachedRpcs()
	end)

	self._protocol = Cprotocol:New()
	self._rpc = Crpc:New(self)

	self._pauseTimeStamp = 0
	self._pauseTime = 0

	self._isPauseReceive = false
	self._normalCachedRpcs = {}

	self._specialCachedRpcs = {}
	for funcName, _ in pairs(RPC_USE_CACHE) do
		self._specialCachedRpcs[funcName] = {}
	end
end

local RPC_DISPOSE_IMMEDIATELY = 
{
	["rpc_client_chat"] = true,
	["rpc_client_login_return"] = true,	--服务端有rpc MD5校验，检验不通过会下行rpc_client_update_pto
	["rpc_client_update_pto"] = true,
	["rpc_client_fast_relogin_key"] = true,
	["rpc_client_gohost"] = true,
	["rpc_client_user_login_finish"] = true,
	["rpc_client_encrypt"] = true,
	["rpc_client_use_login_key_return"] = true,
	["rpc_client_fight_command"] = true, -- 战斗协议不能缓存，缓存战斗协议会导致增加1.5s+的战斗初始化时间
	["rpc_client_fight_param"] = true,
}

CProtocolManager.OnSocket = function(self, funcName, args)
	if RPC_DISPOSE_IMMEDIATELY[funcName] then

		if RPC_USE_CACHE[funcName] then
			self._specialCachedRpcs[#self._specialCachedRpcs + 1] = {funcName, args}
		else
			self:receiveRpc(funcName, args)
		end
		return
	end

	self._normalCachedRpcs[#self._normalCachedRpcs + 1] = {funcName, args}
end

CProtocolManager.GetRpc = function(self)
	return self._rpc
end

CProtocolManager.GetProtocol = function(self)
	return self._protocol
end

-- 上行协议LOG输出屏蔽列表
local MASK_ASK_RPC_NAME_LIST = {
	["rpc_server_heartbeat"] = true,
	["rpc_server_move"] = true,
}

-- 下行协议LOG输出屏蔽列表
local MASK_RECEIVE_RPC_NAME_LIST = {
	["rpc_client_move"] = true,
	["rpc_client_whisper_online_list"] = true,
}

--上行协议
CProtocolManager.askRpc = function(self, upRpcName, ...)
	local up_func = self._protocol[upRpcName]
	if not up_func then
		print("up rpc func not implemented:", upRpcName)
		return
	end

	if GlobalCfg.IsDebugRpcLog and not MASK_ASK_RPC_NAME_LIST[upRpcName] then
		local strTab = {}
		for i = 1, select('#', ...) do
			local arg = select(i, ...)
			if type(arg) == "table" then
				arg = table.get_table_str(arg)
			elseif type(arg) ~= "string" then
				arg = tostring(arg)
			end
			table.insert(strTab, arg)
		end
		log(string.format("<color=#ffff00ff> %s:</color>\n", upRpcName), table.concat(strTab, ","))
	end

	up_func(...)
end

--协议下行
CProtocolManager.receiveRpc = function(self, downRpcName, downRpcArgs)
	if self._rpc:IsPrintLog() and not MASK_RECEIVE_RPC_NAME_LIST[downRpcName] then
		print(downRpcName.."@"..os.clock(), table.get_table_str(downRpcArgs))
	end

	downRpcArgs = downRpcArgs or {}

	if GlobalCfg.IsDebugRpcLog and not MASK_RECEIVE_RPC_NAME_LIST[downRpcName] then
		log(string.format("<color=#00ff00ff> %s:</color>", downRpcName), table.str(downRpcArgs))
	end

	local down_func = self._protocol[downRpcName]
	if not down_func then
		print("down rpc func not implemented:", downRpcName)
		return
	end

	local func = function ()
		ProfileSample.BeginSample(downRpcName)
		if #downRpcArgs < 1 then
			down_func(self._protocol)
		else
			down_func(self._protocol, unpack(downRpcArgs))
		end
		ProfileSample.EndSample()
	end

	__TRY__(func)
end

CProtocolManager.Clear = function(self)
end

-- 虚拟暂停网络功能
-- 因为战斗退出的时候无论fight_end时候处理退出, 还是收到enter_sence消息处理退出都会导致问题
-- 所以这里需要参考Q1的做法, 暂停网络接收
-- todo：修改逻辑，避免当self._rpc:OnPacket处理模块协议时再调用PauseReceive不起作用的问题 modify by hy 2016-07-14
CProtocolManager.PauseReceive = function(self, isPause)
	if self._isPauseReceive == isPause then
		return
	end
	self._isPauseReceive = isPause

	-- 恢复时播放所有缓存的网络消息
	if isPause == false then
		if self._pauseTimeStamp ~= 0 then
			self._pauseTime = UnityEngine.Time.realtimeSinceStartup - self._pauseTimeStamp
			self._pauseTimeStamp = 0
		end
	else
		self._pauseTimeStamp = UnityEngine.Time.realtimeSinceStartup
	end
end

CProtocolManager.GetPauseTime = function(self)
	local ret = self._pauseTime
	self._pauseTime = 0
	return ret
end

CProtocolManager.ParseRpc = function(self, cachedRpcs, parseCount, is_break)
	local disposeIdx = 0
	local rpcData = nil
	for i = 1, parseCount do
		if is_break and self._isPauseReceive then break end

		rpcData = cachedRpcs[i]

		if not rpcData then break end

		disposeIdx = i

		self:receiveRpc(rpcData[1], rpcData[2])
	end

	if disposeIdx == 0 then return cachedRpcs end

	local remainIdx = disposeIdx + 1

	local remainPackets = {}
	while(cachedRpcs[remainIdx]) do
		remainPackets[remainIdx - disposeIdx] = cachedRpcs[remainIdx]

		remainIdx = remainIdx + 1
	end
	return remainPackets
end

CProtocolManager.Update = function(self)
	self:UpdateNormalCachedRpcs()
end

CProtocolManager.UpdateNormalCachedRpcs = function(self)
	if self._isPauseReceive then return end

	self._normalCachedRpcs = self:ParseRpc(self._normalCachedRpcs, MAX_RPC_PER_FRAME, true)
end

CProtocolManager.UpdateSpecialCachedRpcs = function(self)
	if self._isPauseReceive then return end

	self._specialCachedRpcs = self:ParseRpc(self._specialCachedRpcs, RPC_CLIENT_CHAT_PARSE_COUNT)
end